﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Test.StringEnums
{
    public abstract class StringConstantBase : IComparable<StringConstantBase>
    {
        private readonly string name;

        /// <summary>
        /// Initializes a new instance of the <see cref="StringConstantBase"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        protected StringConstantBase(string name)
        {
            this.name = name;
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public sealed override string ToString()
        {
            return this.name;
        }

        /// <summary>
        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
        /// <returns>
        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception>
        public sealed override bool Equals(object obj)
        {
            if (obj is string)
                return this.name.Equals(obj);
            else if (obj is StringConstantBase)
                return (this == obj);
            else
                return false;
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>
        /// A hash code for the current <see cref="T:System.Object"/>.
        /// </returns>
        public sealed override int GetHashCode()
        {
            return this.name.GetHashCode();
        }

        /// <summary>
        /// Implements the operator ==.
        /// </summary>
        /// <param name="first">The first.</param>
        /// <param name="second">The second.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator ==(StringConstantBase first, string second)
        {
            return (second == first.ToString());
        }

        /// <summary>
        /// Implements the operator !=.
        /// </summary>
        /// <param name="first">The first.</param>
        /// <param name="second">The second.</param>
        /// <returns>The result of the operator.</returns>
        public static bool operator !=(StringConstantBase first, string second)
        {
            return !(second == first.ToString());
        }

        /// <summary>
        /// Gets the names for a particular constant base type by reflection.
        /// </summary>
        /// <param name="constantType">Type of the constant.</param>
        /// <returns></returns>
        public static string[] GetNames(Type constantType)
        {
            if (constantType.BaseType == typeof(StringConstantBase))
            {
                FieldInfo[] fields = constantType.GetFields();
                string[] names = new string[fields.Length];

                for (int counter = 0; counter < fields.Length; counter++)
                {
                    names[counter] = fields[counter].Name;
                }

                return names;
            }
            else
                throw new ArgumentException("Parameter [constantType] must inherit from type StringConstantBase.");
        }

        #region IComparable<StringConstantBase> Members

        public int CompareTo(StringConstantBase other)
        {
            return this.name.CompareTo(other.ToString());
        }

        #endregion
    }
}
